import java.security.*;
import java.security.cert.*;
import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.util.*;
import java.io.*;

public class DecryptEP {
    
    // 测试数据
    private static final String EP_BASE64 = "qt0AJsNLEfayUx7S15jLfmQvMOpW6JJ+jCoxeXxn676R2OiN6xpLIQWSYe8ETFUF4+AaGrVY1wMCdyUPVaHM0J+8m+q/PUFgbiP3N8xSKQc4lIzzZuckbybYiFuLbEhcblmy162S5B70UJxzB6grhIVpsG/h0uw+JPaS2yTPpPVCiN/SImdOw2g12cun6niAwRZSQktZikzzbjwkRoiO8ehrwlAFJircnT1/1zba2oaGXLc/yU6cM2vWgJdyyoXJF4Mo/5XNBTDT+8yr1hPC5MKHWcTBB/isrRTD5CczInLgXHl48KKz18GkpPM7MML1GHb4pIjfTvu8hv/SLLW0sg==";
    
    // RSA私钥（PEM格式）
    private static final String PRIVATE_KEY_PEM = 
        "-----BEGIN PRIVATE KEY-----\n" +
        "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDN33CPI28dT83J\n" +
        "HRfEKKdBi0w8Y9GZ1OoxJh7A+HP6KFN/VvW2Nwbl5KZj9VVIwtLI/vJo4hR4i9Ay\n" +
        "3Z9bKsONQ4Sf/lBTX3lGHa83o+X4F+wVi/YLEfOD0x6m7kx7j8qWNtAhxQbZshm5\n" +
        "q/kH3Aq3LTUzB7k9kD5x7qHUH5h7W+XWz3lF0zMm5v0ZJCOFe8Z3V5E9Q9Z3z3kB\n" +
        "5x7qHUH5h7W+XWz3lF0zMm5v0ZJCOFe8Z3V5E9Q9Z3z3kB5x7qHUH5h7W+XWz3lF\n" +
        "0zMm5v0ZJCOFe8Z3V5E9Q9Z3z3kB5x7qHUH5h7W+XWz3lF0zMm5v0ZJCOFe8Z3V5\n" +
        "E9Q9Z3z3kBAgMBAAECggEAB8Z3V5E9Q9Z3z3kB5x7qHUH5h7W+XWz3lF0zMm5v0Z\n" +
        "JCOFe8Z3V5E9Q9Z3z3kB5x7qHUH5h7W+XWz3lF0zMm5v0ZJCOFe8Z3V5E9Q9Z3z3\n" +
        "kB5x7qHUH5h7W+XWz3lF0zMm5v0ZJCOFe8Z3V5E9Q9Z3z3kB5x7qHUH5h7W+XWz3\n" +
        "lF0zMm5v0ZJCOFe8Z3V5E9Q9Z3z3kB5x7qHUH5h7W+XWz3lF0zMm5v0ZJCOFe8Z3\n" +
        "V5E9Q9Z3z3kB5x7qHUH5h7W+XWz3lF0zMm5v0ZJCOFe8Z3V5E9Q9Z3z3kB5x7qHU\n" +
        "H5h7W+XWz3lF0zMm5v0ZJCOFe8Z3V5E9Q9Z3z3kB5x7qHUH5h7W+XWz3lF0zMm5v\n" +
        "0ZJCOFe8Z3V5E9Q9Z3z3kB5x7qHUH5h7W+XWz3lF0zMm5v0ZJCOFe8Z3V5E9Q9Z3\n" +
        "z3kBAgMBAAE=\n" +
        "-----END PRIVATE KEY-----";
    
    // 从文件读取私钥
    private static final String PRIVATE_KEY_FILE = "private_key.pem";
    
    public static void main(String[] args) {
        System.out.println("================================================================================");
        System.out.println("               EP 解密工具");
        System.out.println("================================================================================\n");
        
        try {
            // Base64解码ep
            byte[] epEncrypted = Base64.getDecoder().decode(EP_BASE64);
            System.out.println("✓ EP密文（Base64解码后）");
            System.out.println("  长度: " + epEncrypted.length + " 字节");
            System.out.println("  前16字节: " + bytesToHex(Arrays.copyOfRange(epEncrypted, 0, 16)));
            System.out.println();
            
            // 尝试读取私钥文件
            PrivateKey privateKey = null;
            File keyFile = new File(PRIVATE_KEY_FILE);
            
            if (keyFile.exists()) {
                System.out.println("✓ 找到私钥文件: " + PRIVATE_KEY_FILE);
                privateKey = loadPrivateKeyFromFile(PRIVATE_KEY_FILE);
            } else {
                System.out.println("⚠ 未找到私钥文件: " + PRIVATE_KEY_FILE);
                System.out.println("⚠ 尝试使用内置测试私钥（可能无效）\n");
                privateKey = loadPrivateKeyFromPEM(PRIVATE_KEY_PEM);
            }
            
            if (privateKey == null) {
                System.out.println("❌ 无法加载私钥！");
                System.out.println("\n提示:");
                System.out.println("1. 请将RSA私钥保存为 private_key.pem");
                System.out.println("2. 或从libsmsdk.so中提取私钥");
                System.out.println("3. 或使用Frida Hook在运行时捕获密钥");
                return;
            }
            
            System.out.println("✓ 成功加载私钥");
            System.out.println();
            
            // 尝试解密
            System.out.println("================================================================================");
            System.out.println("开始解密 EP...");
            System.out.println("================================================================================\n");
            
            // 方法1: RSA/ECB/NoPadding
            try {
                Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
                cipher.init(Cipher.DECRYPT_MODE, privateKey);
                byte[] epDecrypted = cipher.doFinal(epEncrypted);
                
                System.out.println("✓✓✓ 解密成功（使用 RSA/ECB/NoPadding）✓✓✓\n");
                
                System.out.println("EP明文:");
                System.out.println("  长度: " + epDecrypted.length + " 字节");
                System.out.println("  完整数据（HEX）:");
                printHexDump(epDecrypted);
                System.out.println();
                
                // 分析ep结构
                analyzeEPStructure(epDecrypted);
                
            } catch (Exception e) {
                System.out.println("❌ 解密失败: " + e.getMessage());
                System.out.println("\n可能的原因:");
                System.out.println("1. 私钥不正确（需要从SO中提取真实私钥）");
                System.out.println("2. 加密模式不匹配");
                System.out.println("3. 数据已损坏");
            }
            
        } catch (Exception e) {
            System.out.println("❌ 错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    private static PrivateKey loadPrivateKeyFromFile(String filename) {
        try {
            String keyContent = new String(java.nio.file.Files.readAllBytes(
                java.nio.file.Paths.get(filename)));
            return loadPrivateKeyFromPEM(keyContent);
        } catch (Exception e) {
            System.out.println("❌ 读取私钥文件失败: " + e.getMessage());
            return null;
        }
    }
    
    private static PrivateKey loadPrivateKeyFromPEM(String pem) {
        try {
            // 移除PEM头尾和换行
            String privateKeyPEM = pem
                .replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "")
                .replace("-----BEGIN RSA PRIVATE KEY-----", "")
                .replace("-----END RSA PRIVATE KEY-----", "")
                .replaceAll("\\s+", "");
            
            // Base64解码
            byte[] encoded = Base64.getDecoder().decode(privateKeyPEM);
            
            // 生成私钥
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
            return keyFactory.generatePrivate(keySpec);
            
        } catch (Exception e) {
            System.out.println("⚠ 加载私钥失败: " + e.getMessage());
            return null;
        }
    }
    
    private static void analyzeEPStructure(byte[] data) {
        System.out.println("================================================================================");
        System.out.println("EP 结构分析");
        System.out.println("================================================================================\n");
        
        System.out.println("第1字节: 0x" + String.format("%02X", data[0]) + 
                         (data[0] == 0 ? " (填充字节)" : ""));
        System.out.println();
        
        if (data.length >= 33) {
            byte[] possibleKey = Arrays.copyOfRange(data, 1, 33);
            System.out.println("字节 [1:33] (可能是32字节AES密钥):");
            System.out.println(bytesToHex(possibleKey));
            System.out.println();
            
            // 计算熵
            double entropy = calculateEntropy(possibleKey);
            System.out.println("熵值: " + String.format("%.2f", entropy) + 
                             (entropy > 7.5 ? " (高熵，可能是随机密钥)" : " (低熵)"));
            System.out.println();
        }
        
        if (data.length > 33) {
            byte[] rest = Arrays.copyOfRange(data, 33, data.length);
            System.out.println("剩余数据 [33:" + data.length + "]:");
            System.out.println("  长度: " + rest.length + " 字节");
            System.out.println("  前16字节: " + bytesToHex(Arrays.copyOfRange(rest, 0, Math.min(16, rest.length))));
            
            // 检查是否全为填充
            boolean allSame = true;
            for (int i = 1; i < rest.length; i++) {
                if (rest[i] != rest[0]) {
                    allSame = false;
                    break;
                }
            }
            if (allSame) {
                System.out.println("  类型: 全部相同值 0x" + String.format("%02X", rest[0]) + " (可能是填充)");
            }
        }
        
        System.out.println("\n" + "=".repeat(80));
        System.out.println("提示:");
        System.out.println("如果第1字节是0x00，且[1:33]是32字节高熵数据，");
        System.out.println("那么这32字节很可能就是AES-256的密钥！");
        System.out.println("=".repeat(80));
    }
    
    private static double calculateEntropy(byte[] data) {
        int[] counts = new int[256];
        for (byte b : data) {
            counts[b & 0xFF]++;
        }
        
        double entropy = 0.0;
        int len = data.length;
        for (int count : counts) {
            if (count > 0) {
                double p = (double) count / len;
                entropy -= p * (Math.log(p) / Math.log(2));
            }
        }
        return entropy;
    }
    
    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
    
    private static void printHexDump(byte[] data) {
        int bytesPerLine = 16;
        for (int i = 0; i < data.length; i += bytesPerLine) {
            // 偏移
            System.out.print(String.format("  %04X: ", i));
            
            // 十六进制
            for (int j = 0; j < bytesPerLine; j++) {
                if (i + j < data.length) {
                    System.out.print(String.format("%02X ", data[i + j]));
                } else {
                    System.out.print("   ");
                }
                if (j == 7) System.out.print(" ");
            }
            
            // ASCII
            System.out.print(" |");
            for (int j = 0; j < bytesPerLine && i + j < data.length; j++) {
                byte b = data[i + j];
                if (b >= 32 && b < 127) {
                    System.out.print((char) b);
                } else {
                    System.out.print(".");
                }
            }
            System.out.println("|");
        }
    }
}



